package com.imooc.pan.server.modules.share.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.imooc.pan.bloom.filter.core.BloomFilter;
import com.imooc.pan.bloom.filter.core.BloomFilterManager;
import com.imooc.pan.core.constants.RPanConstants;
import com.imooc.pan.core.exception.RPanBusinessException;
import com.imooc.pan.core.response.ResponseCode;
import com.imooc.pan.core.utils.IdUtil;
import com.imooc.pan.core.utils.JwtUtil;
import com.imooc.pan.core.utils.UUIDUtil;
import com.imooc.pan.server.common.cache.ManualCacheService;
import com.imooc.pan.server.common.config.PanServerConfig;
//import com.imooc.pan.server.common.mq.config.RabbitMQConfig;
import com.imooc.pan.server.common.mq.event.log.ErrorLogEvent;
import com.imooc.pan.server.modules.file.constants.FileConstants;
import com.imooc.pan.server.modules.file.context.CopyFileContext;
import com.imooc.pan.server.modules.file.context.FileDownloadContext;
import com.imooc.pan.server.modules.file.context.QueryFileListContext;
import com.imooc.pan.server.modules.file.entity.RPanUserFile;
import com.imooc.pan.server.modules.file.enums.DelFlagEnum;
import com.imooc.pan.server.modules.file.service.IUserFileService;
import com.imooc.pan.server.modules.file.vo.RPanUserFileVO;
import com.imooc.pan.server.modules.share.constants.ShareConstants;
import com.imooc.pan.server.modules.share.context.*;
import com.imooc.pan.server.modules.share.entity.RPanShare;
import com.imooc.pan.server.modules.share.entity.RPanShareFile;
import com.imooc.pan.server.modules.share.enums.ShareDayTypeEnum;
import com.imooc.pan.server.modules.share.enums.ShareStatusEnum;
import com.imooc.pan.server.modules.share.service.IShareFileService;
import com.imooc.pan.server.modules.share.service.IShareService;
import com.imooc.pan.server.modules.share.mapper.RPanShareMapper;
import com.imooc.pan.server.modules.share.vo.*;
import com.imooc.pan.server.modules.user.entity.RPanUser;
import com.imooc.pan.server.modules.user.service.IUserService;
import io.jsonwebtoken.lang.Collections;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.util.Sets;
//import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lenovo
 * @description 针对表【r_pan_share(用户分享表)】的数据库操作Service实现
 * @createDate 2023-07-27 18:40:16
 */
@Service
@Slf4j
public class ShareServiceImpl extends ServiceImpl<RPanShareMapper, RPanShare>
        implements IShareService {

    @Autowired
    private PanServerConfig config;

    @Autowired
    private IShareFileService iShareFileService;

    @Autowired
    private IUserFileService iUserFileService;

    @Autowired
    private IUserService iUserService;


    @Autowired
    @Qualifier(value = "shareManualCacheService")
    private ManualCacheService<RPanShare> cacheService;

    @Autowired
    private BloomFilterManager manager;

    private static final String BLOOM_FILTER_NAME = "SHARE_SIMPLE_DETAIL";

//    @Autowired
//    private RabbitTemplate rabbitTemplate;

    //@Autowired
    //@Qualifier(value = "defaultStreamProducer")
    //private IStreamProducer producer;
    //private ApplicationContext applicationContext;
    //
    //@Override
    //public void setApplicationContext(ApplicationContext applicationContext) {
    //    this.applicationContext = applicationContext;
    //}

    /**
     * 创建分享链接
     * 1、创建分享实体，保存到数据库
     * 2、保存分享和对应文件的关联关系
     * 3、拼装返回实体并返回
     *
     * @param context
     * @return
     */
    @Override
    @Transactional(rollbackFor = RPanBusinessException.class)
    public RPanShareUrlVO createShare(CreateShareUrlContext context) {
        saveShare(context);
        saveShareList(context);
        RPanShareUrlVO vo = assembleShareVO(context);
        afterCreate(context, vo);
        return vo;
    }

    /**
     * 查询用户的分享列表
     *
     * @param context
     * @return
     */
    @Override
    public List<RPanShareUrlListVO> getShares(QueryShareListContext context) {
        Long userId = context.getUserId();
        return baseMapper.selectShareVOListByUserId(userId);
    }

    /**
     * 取消分享链接
     * 1、校验用户取消权限
     * 2、删除对应的分享记录
     * 3、删除对应的分享文件关联记录
     *
     * @param context
     */
    @Override
    public void cancelShare(CancelShareContext context) {
        checkUserCancelSharePermission(context);
        doCancelShare(context);
        doCancelShareFile(context);
    }

    /**
     * 校验分享码
     * 1、检查分享的状态是否正常
     * 2、校验分享的分享码是否正确
     * 3、生成短时间的 token
     *
     * @param context CheckShareCodeContext
     * @return 临时的 token，利用切面校验 token 是否合法
     */
    @Override
    public String checkShareCode(CheckShareCodeContext context) {
        RPanShare record = checkShareStatus(context.getShareId());
        context.setRecord(record);
        doCheckShareCode(context);
        return generateShareToken(context);
    }

    /**
     * 用户获取了分享码来查询分享的详情
     * <p>
     * 查询分享详情
     * 1、校验分享的状态
     * 2、初始化分享实体
     * 3、查询分享的主体信息
     * 4、查询分享的文件列表
     * 5、查询分享者的信息
     *
     * @param context QueryShareDetailContext
     * @return ShareDetailVO
     */
    @Override
    public ShareDetailVO detail(QueryShareDetailContext context) {
        RPanShare record = checkShareStatus(context.getShareId());
        context.setRecord(record);
        initShareVO(context);
        assembleMainShareInfo(context);
        assembleShareFilesInfo(context);
        assembleShareUserInfo(context);
        return context.getVo();
    }

    /**
     * 查询简单查询的方法
     * <p>
     * 用于用户还没有填写分享码的页面
     * <p>
     * 查询简单查询的方法
     * 1、校验分享的状态
     * 2、初始化分享实体
     * 3、查询分享的主体信息
     * 4、查询分享的文件列表
     * 5、查询分享者的信息
     *
     * @param context QueryShareSimpleDetailContext
     * @return ShareSimpleDetailVO
     */
    @Override
    public ShareSimpleDetailVO simpleDetail(QueryShareSimpleDetailContext context) {
        RPanShare record = checkShareStatus(context.getShareId());
        context.setRecord(record);
        initShareSimpleVO(context);
        assembleMainShareSimpleInfo(context);
        assembleShareSimpleUserInfo(context);
        return context.getVo();
    }

    /**
     * 用户分享码校验通过了
     * <p>
     * 获取下一级的文件列表
     * <p>
     * 1、校验分享的状态
     * 2、校验文件的ID是否在分享的文件列表中
     * 3、查询对应文件的子文件列表，返回
     *
     * @param context
     * @return
     */
    @Override
    public List<RPanUserFileVO> fileList(QueryChildFileListContext context) {
        RPanShare record = checkShareStatus(context.getShareId());
        context.setRecord(record);
        List<RPanUserFileVO> allUserFileRecords =
                checkFileIdIsOnShareStatusAndGetAllShareUserFiles(context.getShareId(), Lists.newArrayList(context.getParentId()));
        Map<Long, List<RPanUserFileVO>> parentIdFileListMap =
                allUserFileRecords.stream().collect(Collectors.groupingBy(RPanUserFileVO::getParentId));
        List<RPanUserFileVO> rPanUserFileVOS = parentIdFileListMap.get(context.getParentId());
        if (CollectionUtils.isEmpty(rPanUserFileVOS)) {
            return Lists.newArrayList();
        }
        return rPanUserFileVOS;
    }

    /**
     * 转存到我的网盘
     * <p>
     * 1、校验分享状态
     * 2、校验文件 ID 是否合法
     * 3、委托文件模块做文件拷贝的操作
     *
     * @param context
     */
    @Override
    public void saveFiles(ShareSaveContext context) {
        checkShareStatus(context.getShareId());
        checkFileIdIsONShareStatus(context.getShareId(), context.getFileIdList());
        doSaveFiles(context);
    }

    /**
     * 分享文件下载
     * 1、校验分享状态
     * 2、校验文件 id 的合法性
     * 3、执行文件下载的动作
     *
     * @param context
     */
    @Override
    public void download(ShareFileDownloadContext context) {
        checkShareStatus(context.getShareId());
        checkFileIdIsONShareStatus(context.getShareId(), Lists.newArrayList(context.getFileId()));
        doDownload(context);
    }

    /**
     * 刷新所有受影响的对应的分享状态
     * <p>
     * 1、查询所有受影响的分享的 id 集合
     * 2、判断每一个分享的对应的文件以及所有的父文件信息均为正常，分享状态变为正常
     * 3、分享文件被删了，父文件信息被删除，变更该分享的状态位有文件被删除
     *
     * @param allAvailableFileIdList
     */
    @Override
    public void refreshShareStatus(List<Long> allAvailableFileIdList) {
        List<Long> shareIdList = getShareIdListByFileIdList(allAvailableFileIdList);
        if (CollectionUtils.isEmpty(shareIdList)) {
            return;
        }
        Set<Long> shareIdSet = Sets.newHashSet(shareIdList);
        shareIdSet.forEach(this::refreshOneShareStatus);
    }

    /**
     * 滚动查询分享 Id
     *
     * @param startId
     * @param limit
     * @return
     */
    @Override
    public List<Long> rollingQueryShareId(long startId, long limit) {
        return baseMapper.rollingQueryShareId(startId, limit);
    }

    // 以下都是缓存模块实现

    /**
     * 根据 ID 删除
     *
     * @param id 主键ID
     */
    @Override
    public boolean removeById(Serializable id) {
        return cacheService.removeById(id);
    }

    /**
     * 删除（根据ID 批量删除）
     *
     * @param idList 主键ID列表
     */
    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        return cacheService.removeByIds(idList);
    }

    /**
     * 根据 ID 选择修改
     *
     * @param entity 实体对象
     */
    @Override
    public boolean updateById(RPanShare entity) {
        return cacheService.updateById(entity.getShareId(), entity);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     */
    @Override
    public boolean updateBatchById(Collection<RPanShare> entityList) {
        if (CollectionUtils.isEmpty(entityList)) {
            return true;
        }
        Map<Long, RPanShare> entityMap = entityList.stream()
                .collect(Collectors.toMap(RPanShare::getShareId, e -> e));
        return cacheService.updateByIds(entityMap);
    }

    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     */
    @Override
    public RPanShare getById(Serializable id) {
        //return cacheService.getById(id);
        return super.getById(id);
    }

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表
     */
    @Override
    public List<RPanShare> listByIds(Collection<? extends Serializable> idList) {
        //return cacheService.getByIds(idList);
        return super.listByIds(idList);
    }

    /********** ShareServiceImpl private methods **********/

    /**
     * 创建分享链接的后置处理，将分享链接保存到布隆过滤器中
     *
     * @param context
     * @param vo
     */
    private void afterCreate(CreateShareUrlContext context, RPanShareUrlVO vo) {
        BloomFilter<Long> bloomFilter = manager.getFilter(BLOOM_FILTER_NAME);
        if (Objects.nonNull(bloomFilter)) {
            bloomFilter.put(context.getRecord().getShareId());
            log.info("create share, add share id to bloom filter, share id is {}",
                    context.getRecord().getShareId());
        }
    }

    /**
     * 刷新一个分享的分享状态
     * <p>
     * 1、查询对应的分享信息，判断有效
     * 2、判断该分享对应的父文件是否正常
     *
     * @param shareId
     */

    private void refreshOneShareStatus(Long shareId) {
        RPanShare record = getById(shareId);
        if (Objects.isNull(record)) {
            return;
        }
        ShareStatusEnum shareStatus = ShareStatusEnum.NORMAL;
        if (!checkShareFileAvailable(shareId)) {
            shareStatus = ShareStatusEnum.FILE_DELETED;
        }
        if (Objects.equals(record.getShareStatus(), shareStatus.getCode())) {
            return;
        }
        doChangeShareStatus(record, shareStatus);
    }

    /**
     * 执行刷新文件分享的动作
     *
     * @param record
     * @param shareStatus
     */
    private void doChangeShareStatus(RPanShare record, ShareStatusEnum shareStatus) {
        record.setShareStatus(shareStatus.getCode());
        //UpdateWrapper<RPanShare> updateWrapper = Wrappers.update();
        //updateWrapper.eq("share_id", shareId);
        //updateWrapper.set("share_status", shareStatus.getCode());
        if (!updateById(record)) {
            ErrorLogEvent errorLogEvent = new ErrorLogEvent(
                    "分享状态失败，请手动更改分享 id = " + record.getShareId() + "的分享状态",
                    RPanConstants.ZERO_LONG);
            // todo errorLogEvent
//            rabbitTemplate.convertAndSend(RabbitMQConfig.ERROR_LOG_EXCHANGE, "errorLog.send",
//                    JSON.toJSONString(errorLogEvent));
            //applicationContext.publishEvent(errorLogEvent);
            //producer.sendMessage(PanChannels.ERROR_LOG_OUTPUT, event);
            //applicationContext.publishEvent(
        }
    }

    /**
     * 检查文件以及所有的父文件均为正常状态
     *
     * @param shareId
     * @return
     */
    private boolean checkShareFileAvailable(Long shareId) {
        List<Long> shareFileIdList = getShareFileIdList(shareId);
        for (Long fileId : shareFileIdList) {
            if (!checkUpFileAvailable(fileId)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查该文件和所有的父文件夹信息均为正常状态
     *
     * @param fileId
     * @return
     */
    private boolean checkUpFileAvailable(Long fileId) {
        RPanUserFile record = iUserFileService.getById(fileId);
        if (Objects.isNull(record)) {
            return false;
        }
        if (Objects.equals(record.getDelFlag(), DelFlagEnum.YES.getCode())) {
            return false;
        }
        if (Objects.equals(record.getParentId(), FileConstants.TOP_PARENT_ID)) {
            return true;
        }
        return checkUpFileAvailable(record.getParentId());
    }

    /**
     * 文件 id 查询对应的分享 id 集合
     *
     * @param allAvailableFileIdList
     * @return
     */
    private List<Long> getShareIdListByFileIdList(List<Long> allAvailableFileIdList) {
        QueryWrapper<RPanShareFile> queryWrapper = Wrappers.query();
        queryWrapper.select("share_id");
        queryWrapper.in("file_id", allAvailableFileIdList);
        List<Long> shareIdList = iShareFileService.listObjs(queryWrapper, value -> (Long) value);
        return shareIdList;
    }

    private void doDownload(ShareFileDownloadContext context) {
        FileDownloadContext fileDownloadContext = new FileDownloadContext();
        fileDownloadContext.setFileId(context.getFileId());
        fileDownloadContext.setUserId(context.getUserId());
        fileDownloadContext.setResponse(context.getResponse());
        iUserFileService.downloadWithoutCheckUser(fileDownloadContext);
    }

    /**
     * 执行保存我的网盘动作
     *
     * @param context ShareSaveContext
     */
    private void doSaveFiles(ShareSaveContext context) {
        CopyFileContext copyFileContext = new CopyFileContext();
        copyFileContext.setFileIdList(context.getFileIdList());
        copyFileContext.setTargetParentId(context.getTargetParentId());
        copyFileContext.setUserId(context.getUserId());
        iUserFileService.copy(copyFileContext);
    }

    private void checkFileIdIsONShareStatus(Long shareId, List<Long> fileIdList) {
        checkFileIdIsOnShareStatusAndGetAllShareUserFiles(shareId, fileIdList);
    }

    /**
     * 校验文件是否处于分享状态，返回该分享的所有文件列表
     *
     * @param shareId
     * @return
     */
    private List<RPanUserFileVO> checkFileIdIsOnShareStatusAndGetAllShareUserFiles(Long shareId, List<Long> fileParentIdList) {
        List<Long> shareFileIdList = getShareFileIdList(shareId);
        if (CollectionUtils.isEmpty(shareFileIdList)) {
            return Lists.newArrayList();
        }
        List<RPanUserFile> allFileRecords = iUserFileService.findAllFileRecordsByFileIdList(shareFileIdList);
        if (CollectionUtils.isEmpty(allFileRecords)) {
            return Lists.newArrayList();
        }
        allFileRecords = allFileRecords.stream()
                .filter(Objects::nonNull)
                .filter(record -> Objects.equals(record.getDelFlag(), DelFlagEnum.NO.getCode()))
                .collect(Collectors.toList());
        List<Long> allFileIdList = allFileRecords.stream().map(RPanUserFile::getFileId).collect(Collectors.toList());
        if (new HashSet<>(allFileIdList).containsAll(fileParentIdList)) {
            return iUserFileService.transferVOList(allFileRecords);
        } else {
            throw new RPanBusinessException(ResponseCode.SHARE_FILE_MISS); // 存在文件被被删除了
        }
    }

    /**
     * 查询分享对应的文件 id
     */
    private List<Long> getShareFileIdList(Long shareId) {
        if (Objects.isNull(shareId)) {
            return Lists.newArrayList();
        }
        QueryWrapper<RPanShareFile> queryWrapper = Wrappers.query();
        queryWrapper.select("file_id");
        queryWrapper.eq("share_id", shareId); // 查询条件的第一个字段
        List<Long> fileIdList = iShareFileService.listObjs(queryWrapper, value -> (Long) value);
        return fileIdList;
    }

    /**
     * 拼装简单分享详情的用户信息
     *
     * @param context
     */
    private void assembleShareSimpleUserInfo(QueryShareSimpleDetailContext context) {
        RPanUser record = iUserService.getById(context.getRecord().getCreateUser());
        if (Objects.isNull(record)) {
            throw new RPanBusinessException("用户信息查询失败");
        }
        ShareUserInfoVO shareUserInfoVO = new ShareUserInfoVO();
        shareUserInfoVO.setUserId(record.getUserId());
        shareUserInfoVO.setUsername(encryptUsername(record.getUsername())); // 只保留用户姓名的前两位，其余位显示 *
        context.getVo().setShareUserInfoVO(shareUserInfoVO);
    }

    private void assembleMainShareSimpleInfo(QueryShareSimpleDetailContext context) {
        RPanShare record = context.getRecord();
        ShareSimpleDetailVO vo = context.getVo();
        vo.setShareId(record.getShareId());
        vo.setShareName(record.getShareName());
    }

    private void initShareSimpleVO(QueryShareSimpleDetailContext context) {
        ShareSimpleDetailVO vo = new ShareSimpleDetailVO();
        context.setVo(vo);
    }

    /**
     * 查询分享者信息
     *
     * @param context
     */
    private void assembleShareUserInfo(QueryShareDetailContext context) {
        RPanUser record = iUserService.getById(context.getRecord().getCreateUser());
        if (Objects.isNull(record)) {
            throw new RPanBusinessException("用户信息查询失败");
        }
        ShareUserInfoVO shareUserInfoVO = new ShareUserInfoVO();
        shareUserInfoVO.setUserId(record.getUserId());
        shareUserInfoVO.setUsername(encryptUsername(record.getUsername())); // 只保留用户姓名的前两位，其余位显示 *
        context.getVo().setShareUserInfoVO(shareUserInfoVO);
    }

    /**
     * 加密用户名称
     *
     * @param username
     * @return
     */
    private String encryptUsername(String username) {
        StringBuffer stringBuffer = new StringBuffer(username);
        stringBuffer.replace(RPanConstants.TWO_INT,
                username.length() - RPanConstants.TWO_INT,
                RPanConstants.COMMON_ENCRYPT_STR); // 左闭右开
        return stringBuffer.toString();
    }

    /**
     * r_pan_user_file 查询当前 shareId 的分享文件
     *
     * @param context
     */
    private void assembleShareFilesInfo(QueryShareDetailContext context) {
        //QueryWrapper<RPanShareFile> queryWrapper = Wrappers.query();
        //queryWrapper.select("file_id");
        //queryWrapper.eq("share_id", context.getShareId()); // 查询条件的第一个字段
        //List<Long> fileIdList = iShareFileService.listObjs(queryWrapper, value -> (Long) value);
        List<Long> fileIdList = getShareFileIdList(context.getShareId());
        QueryFileListContext queryFileListContext = new QueryFileListContext();
        queryFileListContext.setUserId(context.getRecord().getCreateUser());
        queryFileListContext.setDelFlag(DelFlagEnum.NO.getCode());
        queryFileListContext.setFileIdList(fileIdList);
        List<RPanUserFileVO> rPanUserFileVOList = iUserFileService.getFileList(queryFileListContext);
        context.getVo().setRPanUserFileVOList(rPanUserFileVOList);
    }

    private void assembleMainShareInfo(QueryShareDetailContext context) {
        RPanShare record = context.getRecord();
        ShareDetailVO vo = context.getVo();
        vo.setShareId(record.getShareId());
        vo.setShareName(record.getShareName());
        vo.setCreateTime(record.getCreateTime());
        vo.setShareDay(record.getShareDay());
        vo.setShareEndTime(record.getShareEndTime());
    }

    private void initShareVO(QueryShareDetailContext context) {
        ShareDetailVO vo = new ShareDetailVO();
        context.setVo(vo);
    }

    private String generateShareToken(CheckShareCodeContext context) {
        RPanShare record = context.getRecord();
        String token = JwtUtil.generateToken(UUIDUtil.getUUID(), ShareConstants.SHARE_ID,
                record.getShareId(), ShareConstants.ONE_HOUR_LONG);
        return token;
    }

    /**
     * 校验分享码是否正确
     *
     * @param context
     * @return
     */

    private void doCheckShareCode(CheckShareCodeContext context) {
        RPanShare record = context.getRecord();
        if (!Objects.equals(context.getShareCode(), record.getShareCode())) {
            throw new RPanBusinessException("分享码错误");
        }
    }


    /**
     * 检查分享的状态是否正常
     *
     * @param shareId
     * @return
     */
    private RPanShare checkShareStatus(Long shareId) {
        RPanShare record = getById(shareId);
        if (Objects.isNull(record)) {
            throw new RPanBusinessException(ResponseCode.SHARE_CANCELLED);
        }
        if (Objects.equals(ShareStatusEnum.FILE_DELETED.getCode(), record.getShareStatus())) {
            throw new RPanBusinessException(ResponseCode.SHARE_FILE_MISS);
        }
        if (Objects.equals(ShareDayTypeEnum.PERMANENT_VALIDITY.getCode(), record.getShareDayType())) {
            return record;
        }
        if (record.getShareEndTime().before(new Date())) {
            throw new RPanBusinessException(ResponseCode.SHARE_EXPIRE);
        }
        return record;
    }


    private void doCancelShareFile(CancelShareContext context) {
        QueryWrapper<RPanShareFile> queryWrapper = Wrappers.query();
        queryWrapper.in("share_id", context.getShareIdList());
        queryWrapper.eq("create_user", context.getUserId());
        if (!iShareFileService.remove(queryWrapper)) {
            throw new RPanBusinessException("取消文件分享失败");
        }
    }

    /**
     * 取消文件分享的动作
     *
     * @param context
     */
    private void doCancelShare(CancelShareContext context) {
        List<Long> shareIdList = context.getShareIdList();
        if (!removeByIds(shareIdList)) {
            throw new RPanBusinessException("取消文件分享失败");
        }
    }

    /**
     * 校验用户是否有取消分享的权限
     *
     * @param context
     */
    private void checkUserCancelSharePermission(CancelShareContext context) {
        List<Long> shareIdList = context.getShareIdList();
        Long userId = context.getUserId();
        List<RPanShare> records = listByIds(shareIdList);
        if (Collections.isEmpty(records)) {
            throw new RPanBusinessException("您无权操作取消分享的动作");
        }
        for (RPanShare record : records) {
            if (!Objects.equals(userId, record.getCreateUser())) {
                throw new RPanBusinessException("您无权操作取消分享的动作");
            }
        }
    }


    private RPanShareUrlVO assembleShareVO(CreateShareUrlContext context) {
        RPanShare record = context.getRecord();
        RPanShareUrlVO vo = new RPanShareUrlVO();
        vo.setShareId(record.getShareId());
        vo.setShareName(record.getShareName());
        vo.setShareUrl(record.getShareUrl());
        vo.setShareCode(record.getShareCode());
        vo.setShareStatus(record.getShareStatus());
        return vo;
    }

    /**
     * 保存分享和分享文件的关联关系
     *
     * @param context CreateShareUrlContext
     */
    private void saveShareList(CreateShareUrlContext context) {
        SaveShareFilesContext saveShareFilesContext = new SaveShareFilesContext();
        saveShareFilesContext.setShareId(context.getRecord().getShareId());
        saveShareFilesContext.setShareFileIdList(context.getShareFileIdList());
        saveShareFilesContext.setUserId(context.getUserId());
        iShareFileService.saveShareFiles(saveShareFilesContext);
    }


    /**
     * 拼装分享实体并保存到 r_pan_share 表中
     *
     * @param context
     */
    private void saveShare(CreateShareUrlContext context) {
        RPanShare record = new RPanShare();
        record.setShareId(IdUtil.get());
        record.setShareName(context.getShareName());
        record.setShareType(context.getShareType());
        record.setShareDayType(context.getShareDayType());
        Integer shareDay = ShareDayTypeEnum.getShareDayByCode(context.getShareDayType());
        if (Objects.equals(RPanConstants.MINUS_ONE_INT, shareDay)) {
            throw new RPanBusinessException("分享天数非法");
        }
        record.setShareDay(shareDay);
        record.setShareEndTime(DateUtil.offsetDay(new Date(), shareDay));
        record.setShareUrl(createShareUrl(record.getShareId()));
        record.setShareCode(createShareCode());
        record.setShareStatus(ShareStatusEnum.NORMAL.getCode());
        record.setCreateUser(context.getUserId());
        record.setCreateTime(new Date());
        if (!save(record)) {
            throw new RPanBusinessException("保存分享信息失败");
        }
        context.setRecord(record);
    }

    /**
     * 创建分享的分享码
     *
     * @return
     */
    private String createShareCode() {
        return RandomStringUtils.randomAlphabetic(4).toLowerCase();
    }

    /**
     * 创建分享的 url
     *
     * @param shareId
     * @return
     */
    private String createShareUrl(Long shareId) {
        if (Objects.isNull(shareId)) {
            throw new RPanBusinessException("分享的 id 不能为空");
        }
        String sharePrefix = config.getSharePrefix();
        if (sharePrefix.lastIndexOf(RPanConstants.SLASH_STR) == RPanConstants.MINUS_ONE_INT) {
            sharePrefix += RPanConstants.SLASH_STR;
        }
        // 改成加密 id, 会有一些特殊字符
        return sharePrefix + URLEncoder.encode(IdUtil.encrypt(shareId));
    }
}




